import etcd3
import json
from threading import Event
from typing import Any, Dict, Optional

class EtcdConfigManager:
    def __init__(self, host: str = 'localhost', port: int = 2379):
        self.client = etcd3.client(host=host, port=port)
        self.watch_event = Event()
    
    def put_config(self, key: str, value: Any) -> bool:
        """存储配置"""
        try:
            if isinstance(value, (dict, list)):
                value = json.dumps(value)
            self.client.put(key, value)
            return True
        except Exception as e:
            print(f"Failed to put config: {e}")
            return False
    
    def get_config(self, key: str, default: Any = None) -> Optional[Any]:
        """获取配置"""
        try:
            value, _ = self.client.get(key)
            if value is None:
                return default
            try:
                return json.loads(value.decode('utf-8'))
            except json.JSONDecodeError:
                return value.decode('utf-8')
        except Exception as e:
            print(f"Failed to get config: {e}")
            return default
    
    def delete_config(self, key: str) -> bool:
        """删除配置"""
        try:
            return self.client.delete(key)
        except Exception as e:
            print(f"Failed to delete config: {e}")
            return False
    
    def watch_config(
        self, 
        key: str, 
        callback: callable,
        timeout: Optional[int] = None
    ) -> None:
        """监听配置变更"""
        def watch_callback(event):
            try:
                value = event.events[0].value
                if value:
                    try:
                        value = json.loads(value.decode('utf-8'))
                    except json.JSONDecodeError:
                        value = value.decode('utf-8')
                    callback(value)
            except Exception as e:
                print(f"Watch callback error: {e}")
        
        try:
            self.watch_event.clear()
            self.client.add_watch_callback(key, watch_callback)
            self.watch_event.wait(timeout)
        except Exception as e:
            print(f"Watch failed: {e}")
        finally:
            self.client.cancel_watch()
    
    def stop_watch(self):
        """停止监听"""
        self.watch_event.set()

# 示例用法
if __name__ == "__main__":
    config_manager = EtcdConfigManager()
    
    # 1. 存储配置
    app_config = {
        "database": {
            "host": "db.example.com",
            "port": 3306,
            "user": "admin"
        },
        "cache": {
            "enabled": True,
            "ttl": 3600
        }
    }
    config_manager.put_config("/configs/myapp", app_config)
    
    # 2. 读取配置
    config = config_manager.get_config("/configs/myapp")
    print("Current config:", config)
    
    # 3. 监听配置变更
    def config_change_handler(new_config):
        print("\nConfig changed to:", new_config)
    
    print("\nWatching for config changes... (Ctrl+C to stop)")
    try:
        config_manager.watch_config("/configs/myapp", config_change_handler)
    except KeyboardInterrupt:
        config_manager.stop_watch()